#pragma once
#include "Socket.hpp"
#include <iostream>
#include <memory>
#include <sys/select.h>

class SelectServer
{
    const static int gnum = sizeof(fd_set) * 8;
    const static int gdefaultfd = -1;

private:
    // void HandlerEvent(fd_set &rfds)
    // {
    //     InetAddr peer;
    //     if (FD_ISSET(_listensock->Sockfd(), &rfds))
    //     {
    //         int sockfd = _listensock->Accepter(&peer);
    //         LOG(DEBUG, "get a new link,client info %s:%d\n", peer.IP().c_str(), peer.Port());
    //     }
    // }
    void Accepter()
    {
        InetAddr addr;
        int sockfd = _listensock->Accepter(&addr);
        // 添加到监视rfds集
        for (int i = 0; i < gnum; i++)
        {
            if (_fd_array[i] == gdefaultfd)
            {
                _fd_array[i] = sockfd;
                break;
            }
        }
    }
    void HandlerIO(int i)
    {
        // 直接开读，一定不会阻塞
        char buffer[1024];
        ssize_t n = recv(_fd_array[i], buffer, sizeof(buffer)-1,0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say# " << buffer << std::endl;
            std::string content = "<html><body><h1>hello bite</h1></body></html>";
            std::string echo_str = "HTTP/1.0 200 OK\r\n";
            echo_str += "Content-Type: text/html\r\n";
            echo_str += "Content-Length: " + std::to_string(content.size()) + "\r\n\r\n";
            echo_str += content;
            // echo_str += buffer;
            ::send(_fd_array[i], echo_str.c_str(), echo_str.size(), 0); // 临时方案
        }
        else if (n == 0)
        {
            LOG(INFO, "client quit...\n");
            // 关闭fd
            ::close(_fd_array[i]);
            // select 不要在关心这个fd了
            _fd_array[i] = gdefaultfd;
        }
        else
        {
            LOG(ERROR, "recv error\n");
            // 关闭fd
            ::close(_fd_array[i]);
            // select 不要在关心这个fd了
            _fd_array[i] = gdefaultfd;
        }
    }
    void HandlerEvent(fd_set &rfds)
    {
        for (int i = 0; i < gnum; i++)
        {
            if (_fd_array[i] == gdefaultfd)
                continue;
            if (FD_ISSET(_fd_array[i], &rfds)) // 就绪且合法
            {
                if (_fd_array[i] == _listensock->Sockfd())
                    Accepter();
                else
                    HandlerIO(i);
            }
        }
    }

public:
    SelectServer(uint16_t port)
        : _port(port), _listensock(std::make_unique<tcp_Socket>())
    {
        _listensock->BuildListenSocket(_port);
    }
    void Init()
    {
        for (int i = 0; i < gnum; i++)
        {
            _fd_array[i] = gdefaultfd;
        }
        _fd_array[0] = _listensock->Sockfd();
    }
    void Loop()
    {
        while (true)
        {
            // 临时创建fd集
            fd_set rfds;
            FD_ZERO(&rfds); // 宏函数

            struct timeval timeout = {30, 0};

            int maxfd = gdefaultfd;
            // 添加关心的fd到rfds
            for (int i = 0; i < gnum; i++)
            {
                if (_fd_array[i] == gdefaultfd)
                    continue;
                FD_SET(_fd_array[i], &rfds);
                if (maxfd < _fd_array[i])
                    maxfd = _fd_array[i];
            }

            // 进行多路转接
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr /*&timeout*/);
            if (n > 0)
            {
                LOG(INFO, "have event ready,n: %d\n", n);
                HandlerEvent(rfds);
                PrintDebug();
            }
            else if (n == 0)
            {
                LOG(DEBUG, "time out,%d,%d\n", timeout.tv_sec, timeout.tv_usec);
                continue;
            }
            else if (n == -1)
            {
                LOG(ERROR, "select error\n");
                break;
            }
        }
    }
    void PrintDebug()
    {
        std::cout << "fd list: ";
        for (int i = 0; i < gnum; i++)
        {
            if (_fd_array[i] == gdefaultfd)
                continue;
            std::cout << _fd_array[i] << " ";
        }
        std::cout << "\n";
    }
    ~SelectServer() {}

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensock;
    int _fd_array[gnum];
};